package body Algorithmes is
    
	function Comparer(A,B: Commande) return Boolean is
	begin
	    -- Nous voulons les commandes satisfaites et erronees a la fin de la liste de commandes
        if (Get_Etat(B) /= 'A') then
            return False;
        elsif (Get_Etat(A) /= 'A') then       
            return True;
        else  
            -- Les deux commandes sont en attente
            if (Get_Categorie(Get_Piece_Assoc(A)) /= Get_Categorie(Get_Piece_Assoc(B))) then
                
                -- La categorie n'est pas la meme
                return (Get_Categorie(Get_Piece_Assoc(A)) > Get_Categorie(Get_Piece_Assoc(B)));
                
            else
            
                -- La categorie est la meme
                if (Get_Largeur(Get_Dimension(Get_Piece_Assoc(A))) 
                    /= Get_Largeur(Get_Dimension(Get_Piece_Assoc(B)))) then

                                    
                    return (Get_Largeur(Get_Dimension(Get_Piece_Assoc(A))) 
                            < Get_Largeur(Get_Dimension(Get_Piece_Assoc(B))));
                            
                else
                
                    -- La largeur est la meme
                    if (Get_Hauteur(Get_Dimension(Get_Piece_Assoc(A)))
                        /= Get_Hauteur(Get_Dimension(Get_Piece_Assoc(B)))) then
                        
                        return (Get_Hauteur(Get_Dimension(Get_Piece_Assoc(A)))
                                < Get_Hauteur(Get_Dimension(Get_Piece_Assoc(B))));
                                
                    else
                    
                        -- La hauteur est la meme
                        return Get_Id(A) > Get_Id(B);
                    end if;
                end if;
            end if;
        end if;
            
	end Comparer;
	        
	procedure Planifier (
        Stock : in out Liste_Plaques.T_Liste;
        Liste_Comm : in out Liste_Commandes.T_Liste) is
		
		procedure Traiter (Comm : in out Commande) is
			L_Morceau_Adapte : Liste_Plaques.T_Liste;
			Morceau_Adapte : Plaque;
			Taille_Orig, Pos_Orig : Dimension;
	
			Colonne_Courante, Colonne_Droite : Plaque;
			Piece_A_Placer : Ptr_Piece;
	
		begin
		    -- Ne traiter que les commandes en attente
			if (Get_Etat(Comm) = 'A') then
			
				Piece_A_Placer := Get_Piece_Assoc(Comm);
			
				Trier_Plaques(Stock, Comm);
				
				L_Morceau_Adapte := Liste_Plaques.Cherche_Plaque_Adaptee(Stock, Piece_A_Placer.all);
				
				if not Liste_Plaques.Liste.Est_Vide(L_Morceau_Adapte) then
					-- Il existe au moins une plaque (ou morceau de plaque) pouvant accueillir la piece analysee
					Morceau_Adapte := Liste_Plaques.Liste.GetCourant(L_Morceau_Adapte);
					
					Taille_Orig := Get_Taille(Morceau_Adapte);
					Pos_Orig := Get_Position(Morceau_Adapte);
				
					-- Positionner la piece en haut a gauche
					Set_Emplacement(Piece_A_Placer.all, Emplacements.Creer(Get_Id(Morceau_Adapte), Pos_Orig));
								
					Set_Etat(Comm, 'S'); -- La commande est satisfaite
				
					-- Mettre a jour la plaque (morceau: colonne courante)
					Colonne_Courante := Creer(Morceau_Adapte, 
						Taille => Dim(
							Largeur => Get_Largeur(Get_Dimension(Piece_A_Placer.all)),
							Hauteur => Get_Hauteur(Taille_Orig) - Get_Hauteur(Get_Dimension(Piece_A_Placer.all))
							),
						Position => Dim(
							Largeur => Get_Largeur(Pos_Orig),
							Hauteur => Get_Hauteur(Pos_Orig) + Get_Hauteur(Get_Dimension(Piece_A_Placer.all))
							)
						);
				
					Liste_Plaques.Liste.SetCourant(L_Morceau_Adapte, Colonne_Courante);
				
					-- Morceau: colonne de droite
					if Get_Hauteur(Pos_Orig) = 0 then
						-- Ajouter la colonne de droite dans la liste de morceaux   		
						Colonne_Droite := Creer(Morceau_Adapte, 
							Taille => Dim(
								Largeur => Get_Largeur(Taille_Orig) - Get_Largeur(Get_Dimension(Piece_A_Placer.all)),
								Hauteur => Get_Hauteur(Taille_Orig)
								),
							Position => Dim(
								Largeur => Get_Largeur(Pos_Orig) + Get_Largeur(Get_Dimension(Piece_A_Placer.all)),
								Hauteur => Get_Hauteur(Pos_Orig)
								)
							);
					
						Liste_Plaques.Liste.Ajout_Apres(L_Morceau_Adapte, Colonne_Droite);
					end if;
				end if;
			end if;
		end Traiter;
	
		procedure Traiter_Tous is new Liste_Commandes.Liste.Map(Traiter);
	

	begin
		Trier(Liste_Comm);
		Traiter_Tous(Liste_Comm);
	end Planifier;
    
    procedure Annuler (
        Stock : in out Liste_Plaques.T_Liste;
        Comm_Supprimee : in Commandes.Commande;
        Liste_Fin : in out Liste_Plaques_Finales.T_Liste
        ) is
        Piece_A_Supprimer : Pieces.Piece;
        L_Plaque_Finale : Liste_Plaques_Finales.T_Liste;
    begin
        -- Est-ce que la commande a deja ete planifiee ?
        if Commandes.Get_Etat(Comm_Supprimee) = 'S' then
            -- Rendre disponible l'emplacement precedemment occupe par la piece
            Piece_A_Supprimer := Commandes.Get_Piece_Assoc(Comm_Supprimee);
            Liste_Plaques.Ajouter (Stock, Plaques.Creer(Piece_A_Supprimer));
        end if;
    end Annuler;    
end Algorithmes;